package com.announcement.dao.Impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.announcement.dao.BaseDao;
import com.announcement.entity.vo.Page;

public class BaseDaoImpl<T, PK extends java.io.Serializable> implements
		BaseDao<T, Serializable> {

	// 日志输出类

	protected static final Logger LOGGER = LoggerFactory

	.getLogger(BaseDaoImpl.class);

	// 泛型反射类

	private Class<T> entityClass;

	// 通过反射获取子类确定的泛型类

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public BaseDaoImpl() {

		Type genType = getClass().getGenericSuperclass();

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		entityClass = (Class) params[0];

	}

	/*
	 * 
	 * 注入sessionFactory
	 */

	@Autowired
	@Qualifier("sessionFactory")
	private SessionFactory sessionFactory;

	public Session openSession() {
		return sessionFactory.openSession();
	}

	public Session getSession() {

		// 事务必须是开启的(Required)，否则获取不到

		return sessionFactory.getCurrentSession();

	}

	/*
	 * 
	 * 保存PO
	 */
	@Override
	public Serializable save(T entity) {

		return (Serializable) getSession().save(entity);

	}

	/*
	 * 
	 * 保存或更新PO
	 */
	@Override
	public void saveOrUpdate(T entity) {

		getSession().saveOrUpdate(entity);

	}

	/*
	 * 
	 * 更新PO
	 */
	@Override
	public void update(T entity) {

		getSession().update(entity);

	}

	/*
	 * 
	 * 合并PO
	 */
	@Override
	public void merge(T entity) {

		getSession().merge(entity);

	}

	/*
	 * 
	 * 根据id删除PO
	 */
	@Override
	public void delete(Serializable id) {

		getSession().delete(this.get(id));

	}

	/*
	 * 
	 * 删除PO
	 */
	@Override
	public void deleteObject(T entity) {

		getSession().delete(entity);

	}

	/*
	 * 
	 * 根据id判断PO是否存在
	 */
	@Override
	public boolean exists(Serializable id) {

		return get(id) != null;

	}

	/*
	 * 
	 * 根据id加载PO
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T load(Serializable id) {

		return (T) getSession().load(this.entityClass, id);

	}

	/*
	 * 
	 * 根据id获取PO
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T get(Serializable id) {

		return (T) getSession().get(this.entityClass, id);

	}

	/*
	 * 
	 * 获取PO总数(默认为entityClass)
	 */
	@Override
	public int countAll() {

		Criteria criteria = createCriteria();

		return Integer.valueOf(criteria.setProjection(Projections.rowCount())

		.uniqueResult().toString());

	}

	/*
	 * 
	 * 根据Criteria查询条件，获取PO总数
	 */
	@Override
	public int countAll(Criteria criteria) {

		return Integer.valueOf(criteria.setProjection(Projections.rowCount())

		.uniqueResult().toString());

	}

	/*
	 * 
	 * 删除所有
	 */
	@Override
	public void deleteAll(Collection<?> entities) {

		if (entities == null)

			return;

		for (Object entity : entities) {

			getSession().delete(entity);

		}

	}

	/*
	 * 
	 * 获取全部对象
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list() {

		return createCriteria().list();

	}

	/*
	 * 
	 * 获取对象列表根据Criteria
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list(Criteria criteria) {

		return criteria.list();

	}

	/*
	 * 
	 * 离线查询
	 */
	@Override
	@SuppressWarnings({ "unchecked", "hiding" })
	public <T> List<T> list(DetachedCriteria criteria) {

		return (List<T>) list(criteria.getExecutableCriteria(getSession()));

	}

	/*
	 * 
	 * 获取全部对象，支持排序
	 * 
	 * @param orderBy
	 * 
	 * @param isAsc
	 * 
	 * @return
	 */

	@SuppressWarnings("unchecked")
	public List<T> list(String orderBy, boolean isAsc) {

		Criteria criteria = createCriteria();

		if (isAsc) {

			criteria.addOrder(Order.asc(orderBy));

		} else {

			criteria.addOrder(Order.desc(orderBy));

		}

		return criteria.list();

	}

	/*
	 * 
	 * 按属性查找对象列表，匹配方式为相等
	 * 
	 * @param propertyName
	 * 
	 * @param value
	 * 
	 * @return
	 */
	@Override
	public List<T> list(String propertyName, Object value) {

		Criterion criterion = Restrictions

		.like(propertyName, "%" + value + "%");

		return list(criterion);

	}

	/*
	 * 
	 * 根据查询条件获取数据列表
	 */
	@SuppressWarnings("unchecked")
	private List<T> list(Criterion criterion) {

		Criteria criteria = createCriteria();

		criteria.add(criterion);

		return criteria.list();

	}

	/*
	 * 
	 * 按Criteria查询对象列表
	 * 
	 * @param criterions数量可变的Criterion
	 * 
	 * @param criterions
	 * 
	 * @return
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list(Criterion... criterions) {

		return createCriteria(criterions).list();

	}

	/*
	 * 
	 * 按属性查找唯一对象，匹配方式为相等
	 * 
	 * @param propertyName
	 * 
	 * @param value
	 * 
	 * @return
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T uniqueResult(String propertyName, Object value) {

		Criterion criterion = Restrictions.eq(propertyName, value);

		return (T) createCriteria(criterion).uniqueResult();

	}

	/*
	 * 
	 * 按Criteria查询唯一对象
	 * 
	 * 
	 * 
	 * @param criterions数量可变的Criterion
	 * 
	 * 
	 * 
	 * @param criterions
	 * 
	 * 
	 * 
	 * @return
	 */
	@Override
	public T uniqueResult(Criterion... criterions) {

		Criteria criteria = createCriteria(criterions);

		return uniqueResult(criteria);

	}

	/*
	 * 
	 * 按Criteria查询唯一对象
	 * 
	 * @param criterions
	 * 
	 * @return
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T uniqueResult(Criteria criteria) {

		return (T) criteria.uniqueResult();

	}

	/*
	 * 
	 * 为Criteria添加distinct transformer
	 * 
	 * @param criteria
	 * 
	 * @return
	 */

	// 认为没用
	@Override
	public Criteria distinct(Criteria criteria) {

		// 将结果集进行一次封装，封装成DISTINCT_ROOT_ENTITY对象，方便service层代码使用

		criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

		return criteria;

	}

	/*
	 * 
	 * 强制清空session
	 */
	@Override
	public void flush() {

		getSession().flush();

	}

	/*
	 * 
	 * 清空session
	 */
	@Override
	public void clear() {

		getSession().clear();

	}

	/*
	 * 
	 * 创建Criteria实例
	 */
	@Override
	public Criteria createCriteria() {

		return getSession().createCriteria(entityClass);

	}

	/*
	 * 
	 * 根据Criterion条件创建Criteria
	 * 
	 * @param criterions数量可变的Criterion
	 */
	@Override
	public Criteria createCriteria(Criterion... criterions) {

		Criteria criteria = createCriteria();

		for (Criterion c : criterions) {

			criteria.add(c);

		}

		return criteria;

	}

	/*
	 * 
	 * 分页 封装到 List 对象 中 By Criteria
	 * 
	 * @param
	 * 
	 * @return
	 */
	@Override
	public List<T> findPageByCriteria(Criteria criteria, int pageIndex,
			int pageSize) {

		// 设置起始结果数

		criteria.setFirstResult((pageIndex - 1) * pageSize);

		// 返回的最大结果集

		criteria.setMaxResults(pageSize);

		return list(criteria);

	}

	/**
	 * 分页 封装到 Page 对象 中 By HQL
	 */
	@Override
	public Page<T> findPage(int pageSize, int pageIndex, String hql) {
		int startpage;
		if (pageIndex == 0) {
			startpage = 1;
		} else {
			startpage = pageIndex;
		}
		Page<T> page = new Page<T>();
		int allRow = getSession().createQuery(hql).list().size();
		int totalPage = Page.countTotalPage(pageSize, allRow);
		/**
		 * 当前 页的 记录行
		 */
		int pageStartRow = Page.countOffset(pageSize, startpage);

		if (pageStartRow < 0) {
			pageStartRow = 0;
		}
		final int offset = pageStartRow;
		final int length = pageSize;
		final int currentPage = Page.countCurrentPage(startpage);

		List<T> list = this.getPage(length, offset, hql);
		page.setPageSize(pageSize);
		page.setCurrentPage(currentPage);
		page.setAllRow(allRow);
		page.setTotalPage(totalPage);
		page.setList(list);
		page.init();
		return page;
	}

	/**
	 * 分页 封装到 List 对象 中 By HQL
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> getPage(int pageSize, int pageIndex, String hql) {
		List<T> list = new ArrayList<T>();
		Query query = getSession().createQuery(hql);
		query.setFirstResult(pageIndex);
		query.setMaxResults(pageSize);
		list = query.list();
		return list;
	}
}